package tr.edu.boun.phys.springmassmodel.audio;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class Audio implements Runnable {
	
	private static final int SAMPLE_RATE = 44100;
    private static final int BIT_DEPTH = 16;
    private static final int N_CHANNELS = 1;
    private static final boolean LITTLE_ENDIAN = false;
    private static final int BUFFER_SIZE = 2048*2; // byte cinsinden
    
    private AudioFormat format;
    private SourceDataLine line;
    
	private WaveTable waveTable;
	
	public Audio() {
		int frameSizeInBytes = BIT_DEPTH/8;
        int frameRate = SAMPLE_RATE;
        format = new  AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
                SAMPLE_RATE, BIT_DEPTH, N_CHANNELS, frameSizeInBytes, frameRate, LITTLE_ENDIAN);
        waveTable = new WaveTable(128);
	}

	public void open() {
        
        DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format);
        
        if(AudioSystem.isLineSupported(sourceInfo)) {
            try {
                line = (SourceDataLine) AudioSystem.getLine(sourceInfo);
                line.open(format, BUFFER_SIZE);
                System.out.println("Output line opened with a buffer size: "
                        + line.getBufferSize());
            } catch (LineUnavailableException ex) {
                ex.printStackTrace();
            }            
        }
	}
	
	public void close() {
		// wait until all data is played, then close the line
		line.drain( );
		line.stop( );
	    line.close( );
	}
	
	public void run() {
        line.start();
        //System.out.println("Engine started.");
        int softBufferSize = 512;
        byte[] dataSynthesis = new byte[softBufferSize*2];       
        
        int numBytesWritten;
        
        while(true) {
        	int availableBufferSpace = line.available();
        	
        	if(availableBufferSpace > softBufferSize*2) {
        		/* put the synthesis code in this if */       		
        		int[] finalMix = waveTable.calculateSamples(softBufferSize);
        		
        		for(int i=0, n=0; n<softBufferSize; i+=2, n++) {
        			dataSynthesis[i]   = (byte)( finalMix[n]     & 0xFF);
        			dataSynthesis[i+1] = (byte)((finalMix[n]>>8) & 0xFF);                                    
        		}        
        	
        		numBytesWritten = line.write(dataSynthesis, 0, dataSynthesis.length);
        	}
        }
	}
	
	public WaveTable getWaveTable() {
		return waveTable;
	}

	public void setWaveTable(WaveTable waveTable) {
		this.waveTable = waveTable;
	}		
}